package com.Hermes.NSP;

import com.Hermes.Omega.PK;
import com.Hermes.Proxy.CT;
import com.Hermes.User.tokenNode;
import it.unisa.dia.gas.jpbc.Element;

import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;

public class EncNavigation {
    //Some Enumerate
    private final int RIGHT = 0;
    private final int LEFT = 1;
    private final int ON = 2;
    Random ram = new Random();
    private PK pk;

    //    private final int
    private int ri() {
        return ram.nextInt(1000) + 9000;
    }

    public int SecureOrienting(tokenNode Is, tokenNode Id, tokenNode Ip) throws NoSuchAlgorithmException {
        if (Id.equals(Ip)) {
            return ON;
        }
        int cb3 = 0;
        EncNode ens = EncGraph.nodeSet.get(Is),
                end = EncGraph.nodeSet.get(Is),
                enp = EncGraph.nodeSet.get(Is);

//        BigInteger r=new BigInteger(String.valueOf(ri));
        Element re = pk.get_G1().newElement(ri()).getImmutable();
        EncVec EOV = new EncVec(end.getEy().div(ens.getEy()).getImmutable(), ens.getEx().div(end.getEx()).getImmutable());
        EncVec ESP = new EncVec(enp.getEy().div(ens.getEy()).getImmutable(), enp.getEx().div(ens.getEx()).getImmutable());
        Element encs = EncVecTools.ENCS_SD_SP(ESP, EOV).getImmutable();
        Element encsr = encs.mul(re);
        cb3 = CT.CT_CMP(encsr, re);
        if (cb3 == 1) return LEFT;
        return RIGHT;

    }


    public StopSet[] SecureSplitting(tokenNode Is, tokenNode Ib, StopSet Psemi) throws NoSuchAlgorithmException {
        StopSet[] res = new StopSet[2];
        StopSet PsemiL = new StopSet(), PsemiR = new StopSet();
        int side = ON;
        for (tokenNode node : Psemi.set) {
            side = SecureOrienting(Is, Ib, node);
            if (side == LEFT) {
                PsemiL.set.add(node);
            } else {
                PsemiR.set.add(node);
            }
        }
        res[0] = PsemiL;
        res[1] = PsemiR;
        return res;
    }

    /**
     * 安全分组，整个地图的点将分成三块
     *
     * @param tokens
     * @return StopSet[];[0]=Plow,[1]=Pmid,[2]=Phigh
     */
    public StopSet[] SecureGrouping(ArrayList<tokenNode> tokens) throws NoSuchAlgorithmException {

        StopSet[] res = new StopSet[3];
        ArrayList<tokenNode> tokens1 = tokens;

        if (tokens1.size() == 2) {
            return res;
        }
        int cb1 = 0, cb2 = 0;

        EncNode s = EncGraph.nodeSet.get(tokens1.get(0));
        EncNode d = EncGraph.nodeSet.get(tokens1.get(1));
        EncVec esd = new EncVec(s, d);
        EncVec eds = new EncVec(d, s);
        EncVecPreProcessingTools tools1 = new EncVecPreProcessingTools(esd, pk);
        EncVecPreProcessingTools tools2 = new EncVecPreProcessingTools(eds, pk);
        for (tokenNode tokenNode : tokens1) {
            EncNode p = EncGraph.nodeSet.get(tokenNode);
            EncVec esp = new EncVec(p, s);
            Element e1 = tools1.ENCS_SD_SP(esp);
            Element r = pk.get_G1().newElement(ri()).getImmutable();
            Element e1r = e1.mul(r).getImmutable();
            EncVec edp = new EncVec(d, p);
            cb1 = CT.CT_CMP(e1r, r);
            Element r1 = pk.get_G1().newElement(ri()).getImmutable();
            Element e2 = tools2.ENCS_SD_SP(edp);
            Element e2r = e2.mul(r1).getImmutable();
            cb2 = CT.CT_CMP(e2r, r);
            if (cb1 == 1 && cb2 == 0) {
                res[0].set.add(tokenNode);
            } else if (cb1 == 0 && cb2 == 0) {
                res[1].set.add(tokenNode);
            } else if (cb1 == 0 && cb2 == 1) {
                res[2].set.add(tokenNode);
            }
        }
        return res;

    }

    public tokenNode SecureScanning(tokenNode Is, tokenNode Id, tokenNode Ib1,
                                    StopSet PsemiL, StopSet PsemiR, int Side) throws NoSuchAlgorithmException {


        Iterator<tokenNode> itl = PsemiL.set.iterator();
        Iterator<tokenNode> itr = PsemiR.set.iterator();
        int cb4;
        tokenNode t1 = null, t2;

        EncNode s = EncGraph.nodeSet.get(Is);
        EncNode d = EncGraph.nodeSet.get(Id);
        EncNode b1 = EncGraph.nodeSet.get(Ib1);
        EncVec esd = new EncVec(s, d);
        EncVec eds = new EncVec(d, s);
        EncVec ebs = new EncVec(b1, s);
        EncVec esb = new EncVec(s, b1);
        //需要重新写
        EncVec eovSB = EncVecTools.getOV(s, b1);
        EncVec eov = EncVecTools.getOV(s, d);
        //需要重新写
        EncVec evoSB = EncVecTools.getOV(b1, s);
        EncVec evo = EncVecTools.getOV(d, s);

        EncVecPreProcessingTools toolsDS = new EncVecPreProcessingTools(eds, pk);
        EncVecPreProcessingTools toolsOV = new EncVecPreProcessingTools(eov, pk);
        EncVecPreProcessingTools toolsOVSB = new EncVecPreProcessingTools(eovSB, pk);
        EncVecPreProcessingTools toolsVO = new EncVecPreProcessingTools(evo, pk);
        EncVecPreProcessingTools toolsVOSB = new EncVecPreProcessingTools(evoSB, pk);
        EncVecPreProcessingTools toolsBS = new EncVecPreProcessingTools(ebs, pk);


        StopSet P_On_L1 = new StopSet(), P_On_B1S = new StopSet();
        if (Side == LEFT) {
            if (itr.hasNext()) {//如果右半边点集非空，
                for (tokenNode node : PsemiR.set) {//遍历右半边所有的点集
                    EncNode p = EncGraph.nodeSet.get(node);
                    EncVec esp = new EncVec(s, p);
                    Element encs = toolsDS.ENCS_SD_SP(esp).getImmutable();
                    Element re = pk.get_G1().newElement(ri()).getImmutable();
                    Element encsr = encs.mul(re).getImmutable();
                    cb4 = CT.CT_CMP(encsr, re);//比较该点的
                    if (cb4 == 1) P_On_L1.set.add(node);//判断左右，如果在sd，则添加到“在L1线上或者更右边”的集合上
                }
                if (!P_On_L1.set.isEmpty()) {
                    Iterator<tokenNode> itPOL = P_On_L1.set.iterator();
                    t1 = itPOL.next();
                    EncNode p1 = EncGraph.nodeSet.get(t1);

                    while (itPOL.hasNext()) {//从“在L1线上或者更右边”集合中不断迭代点
                        t2 = itPOL.next();
                        EncNode p2 = EncGraph.nodeSet.get(t2);
                        Element enum1 = toolsOV.Enum_P1P2_SD(p1, p2);//从投影距离继续寻找
                        Element re = pk.get_G1().newElement(ri()).getImmutable();
                        Element enum1r = enum1.mul(re);
                        cb4 = CT.CT_CMP(enum1r, re);
                        if (cb4 == 0) t1 = t2;//继续找最右边的点
                    }
                    return t1;
                } else {
                    Iterator<tokenNode> itPR = PsemiR.set.iterator();//调用SO分侧，
                    t1 = itPR.next();
                    while (itPR.hasNext()) {
                        t2 = itPR.next();
                        if (SecureOrienting(t1, Ib1, t2) == RIGHT) {//如果在右侧就继续向右找
                            t1 = t2;
                        }
                    }


                }
            } else if (itl.hasNext()) {//如果左半边集合非空（右半集实在没有结点）
                for (tokenNode node : PsemiL.set) {
                    EncNode p = EncGraph.nodeSet.get(node);
                    EncVec esp = new EncVec(s, p);
                    Element encs = toolsOVSB.ENCS_SD_SP(esp).getImmutable();//注意：左半边的集合应该和在SB1的垂直线进行比较
                    //为什么找垂线上的点（SB1OV）
                    Element re = pk.get_G1().newElement(ri()).getImmutable();
                    Element encsr = encs.mul(re).getImmutable();
                    cb4 = CT.CT_CMP(encsr, re);
                    if (cb4 == 1) P_On_B1S.set.add(node);
                }
                if (!P_On_B1S.set.isEmpty()) {//在B1S这条线上的所有点
                    Iterator<tokenNode> itPOB = P_On_B1S.set.iterator();
                    t1 = itPOB.next();
                    EncNode p1 = EncGraph.nodeSet.get(t1);

                    while (itPOB.hasNext()) {//继续找投影量最大的点
                        t2 = itPOB.next();
                        EncNode p2 = EncGraph.nodeSet.get(t2);
                        Element enum1 = toolsBS.Enum_P1P2_SD(p1, p2);//求的是在B1S上的投影，左半边集上
                        //右半边是SB1上的投影最大
                        Element re = pk.get_G1().newElement(ri()).getImmutable();
                        Element enum1r = enum1.mul(re).getImmutable();
                        cb4 = CT.CT_CMP(enum1r, re);
                        if (cb4 == 0) t1 = t2;
                    }
                    return t1;
                } else {
                    Iterator<tokenNode> itPL = PsemiL.set.iterator();
                    t1 = itPL.next();
                    while (itPL.hasNext()) {
                        t2 = itPL.next();
                        if (SecureOrienting(t1, Ib1, t2) == RIGHT) {
                            t1 = t2;
                        }
                    }


                }
            }
        } else if (Side == RIGHT) {
            if (itl.hasNext()) {
                for (tokenNode node : PsemiL.set) {//应该在左集中寻找
                    EncNode p = EncGraph.nodeSet.get(node);
                    EncVec esp = new EncVec(s, p);
                    Element encs = toolsDS.ENCS_SD_SP(esp).getImmutable();
                    //还是沿着DS的方向上去找，反正已经确定了半边了，现在只要保证在Low区就行
                    Element re = pk.get_G1().newElement(ri()).getImmutable();
                    Element encsr = encs.mul(re).getImmutable();
                    cb4 = CT.CT_CMP(encsr, re);
                    if (cb4 == 1) P_On_L1.set.add(node);
                }
                if (!P_On_L1.set.isEmpty()) {
                    Iterator<tokenNode> itPOL = P_On_L1.set.iterator();
                    t1 = itPOL.next();
                    EncNode p1 = EncGraph.nodeSet.get(t1);

                    while (itPOL.hasNext()) {
                        t2 = itPOL.next();
                        EncNode p2 = EncGraph.nodeSet.get(t2);
                        Element enum1 = toolsVO.Enum_P1P2_SD(p1, p2);//应该统计反方向的投影大小
                        Element re = pk.get_G1().newElement(ri()).getImmutable();
                        Element enum1r = enum1.mul(re);
                        cb4 = CT.CT_CMP(enum1r, re);
                        if (cb4 == 0) t1 = t2;
                    }
                    return t1;
                } else {
                    Iterator<tokenNode> itPL = PsemiL.set.iterator();
                    t1 = itPL.next();
                    while (itPL.hasNext()) {
                        t2 = itPL.next();
                        if (SecureOrienting(t1, Ib1, t2) == LEFT) {//不断的朝左边找
                            t1 = t2;
                        }
                    }


                }
            } else if (itr.hasNext()) {
                for (tokenNode node : PsemiR.set) {
                    EncNode p = EncGraph.nodeSet.get(node);
                    EncVec esp = new EncVec(s, p);
                    Element encs = toolsVOSB.ENCS_SD_SP(esp).getImmutable();//应该是OVSB的相反向量
                    Element re = pk.get_G1().newElement(ri()).getImmutable();
                    Element encsr = encs.mul(re).getImmutable();
                    cb4 = CT.CT_CMP(encsr, re);
                    if (cb4 == 1) P_On_B1S.set.add(node);
                }
                if (!P_On_B1S.set.isEmpty()) {
                    Iterator<tokenNode> itPOB = P_On_B1S.set.iterator();
                    t1 = itPOB.next();
                    EncNode p1 = EncGraph.nodeSet.get(t1);

                    while (itPOB.hasNext()) {
                        t2 = itPOB.next();
                        EncNode p2 = EncGraph.nodeSet.get(t2);
                        Element enum1 = toolsBS.Enum_P1P2_SD(p1, p2);
                        Element re = pk.get_G1().newElement(ri()).getImmutable();
                        Element enum1r = enum1.mul(re).getImmutable();
                        cb4 = CT.CT_CMP(enum1r, re);
                        if (cb4 == 0) t1 = t2;
                    }
                    return t1;
                } else {
                    Iterator<tokenNode> itPR = PsemiR.set.iterator();
                    t1 = itPR.next();
                    while (itPR.hasNext()) {
                        t2 = itPR.next();
                        if (SecureOrienting(t1, Ib1, t2) == LEFT) {
                            t1 = t2;
                        }
                    }


                }
            }
        } else {
            if (itr.hasNext()) {
                for (tokenNode node : PsemiR.set) {
                    EncNode p = EncGraph.nodeSet.get(node);
                    EncVec esp = new EncVec(s, p);
                    Element encs = toolsDS.ENCS_SD_SP(esp).getImmutable();
                    Element re = pk.get_G1().newElement(ri()).getImmutable();
                    Element encsr = encs.mul(re).getImmutable();
                    cb4 = CT.CT_CMP(encsr, re);
                    if (cb4 == 1) P_On_L1.set.add(node);
                }
                if (!P_On_L1.set.isEmpty()) {
                    Iterator<tokenNode> itPOL = P_On_L1.set.iterator();
                    t1 = itPOL.next();
                    EncNode p1 = EncGraph.nodeSet.get(t1);

                    while (itPOL.hasNext()) {
                        t2 = itPOL.next();
                        EncNode p2 = EncGraph.nodeSet.get(t2);
                        Element enum1 = toolsOV.Enum_P1P2_SD(p1, p2);
                        Element re = pk.get_G1().newElement(ri()).getImmutable();
                        Element enum1r = enum1.mul(re);
                        cb4 = CT.CT_CMP(enum1r, re);
                        if (cb4 == 0) t1 = t2;
                    }
                    return t1;
                } else {
                    Iterator<tokenNode> itPR = PsemiR.set.iterator();
                    t1 = itPR.next();
                    while (itPR.hasNext()) {
                        t2 = itPR.next();
                        if (SecureOrienting(t1, Ib1, t2) == RIGHT) {
                            t1 = t2;
                        }
                    }


                }
            }
//            else if (itl.hasNext()) {
//                for (tokenNode node : PsemiL.set) {
//                    EncNode p = EncGraph.nodeSet.get(node);
//                    EncVec esp = new EncVec(s, p);
//                    Element encs = toolsOV.ENCS_SD_SP(esp).getImmutable();
//                    Element re = pk.get_G1().newElement(ri()).getImmutable();
//                    Element encsr = encs.mul(re).getImmutable();
//                    cb4 = CT.CT_CMP(encsr, re);
//                    if (cb4 == 1) P_On_B1S.set.add(node);
//                }
//                if (!P_On_B1S.set.isEmpty()) {
//                    Iterator<tokenNode> itPOB = P_On_B1S.set.iterator();
//                    t1 = itPOB.next();
//                    EncNode p1 = EncGraph.nodeSet.get(t1);
//
//                    while (itPOB.hasNext()) {
//                        t2 = itPOB.next();
//                        EncNode p2 = EncGraph.nodeSet.get(t2);
//                        Element enum1 = toolsOV.Enum_P1P2_SD(p1, p2);
//                        Element re = pk.get_G1().newElement(ri()).getImmutable();
//                        Element enum1r = enum1.mul(re);
//                        cb4 = CT.CT_CMP(enum1r, re);
//                        if (cb4 == 0) t1 = t2;
//                    }
//                    return t1;
//                } else {
//                    Iterator<tokenNode> itPL = PsemiL.set.iterator();
//                    t1 = itPL.next();
//                    while (itPL.hasNext()) {
//                        t2 = itPL.next();
//                        if (SecureOrienting(t1, Ib1, t2) == RIGHT) {
//                            t1 = t2;
//                        }
//                    }
//
//
//                }
//            }
        }
        return t1;
    }

    public tokenNode SecurePulling(tokenNode Is, tokenNode Iss, tokenNode Ib1, tokenNode Ib2,
                                   StopSet PsemiL, StopSet PsemiR, int Side) {
        Iterator<tokenNode> itl = PsemiL.set.iterator();
        Iterator<tokenNode> itr = PsemiR.set.iterator();
        int cb4;
        tokenNode t1 = null, t2;

        EncNode s = EncGraph.nodeSet.get(Is);
        EncNode ss = EncGraph.nodeSet.get(Iss);
        EncNode b1 = EncGraph.nodeSet.get(Ib1);
        EncNode b2 = EncGraph.nodeSet.get(Ib2);

//        EncVec esd = new EncVec(s, d);
//        EncVec eds = new EncVec(d, s);
//        EncVec ebs = new EncVec(b1, s);
//        EncVec esb = new EncVec(s, b1);
//        //需要重新写
//        EncVec eovSB =EncVecTools.getOV(s,b1);
//        EncVec eov = EncVecTools.getOV(s,d);
//        //需要重新写
//        EncVec evoSB =EncVecTools.getOV(b1,s);
//        EncVec evo = EncVecTools.getOV(d,s);
//
//        EncVecPreProcessingTools toolsDS = new EncVecPreProcessingTools(eds, pk);
//        EncVecPreProcessingTools toolsOV = new EncVecPreProcessingTools(eov, pk);
//        EncVecPreProcessingTools toolsOVSB = new EncVecPreProcessingTools(eovSB, pk);
//        EncVecPreProcessingTools toolsVO = new EncVecPreProcessingTools(evo, pk);
//        EncVecPreProcessingTools toolsVOSB = new EncVecPreProcessingTools(evoSB, pk);
//        EncVecPreProcessingTools toolsBS = new EncVecPreProcessingTools(ebs, pk);
        if (Ib1.equals(Ib2)) {
            if (Side == LEFT) {

            } else if (Side == RIGHT) {

            }
        } else {
            if (Side == LEFT) {

            } else if (Side == RIGHT) {

            }
        }
        return Is;
    }

    public tokenNode SecureVerticallyNearestHop(tokenNode Is, tokenNode Id, StopSet P) throws NoSuchAlgorithmException {
        if (P.set.isEmpty()) return Id;
        EncNode es = EncGraph.nodeSet.get(Is);
        EncNode ed = EncGraph.nodeSet.get(Id);
        Iterator<tokenNode> ip = P.set.iterator();
        StopSet PL = new StopSet(), PR = new StopSet();
        tokenNode t1 = ip.next();
        tokenNode t2 = ip.next();
        EncNode ep1 = EncGraph.nodeSet.get(t1);
        EncVec esd = new EncVec(es, ed);
        EncVec eov = EncVecTools.getOV(es, ed);
        EncVec evo = EncVecTools.getOV(ed, es);

        EncVecPreProcessingTools tools = new EncVecPreProcessingTools(esd, pk);
        EncVecPreProcessingTools toolsOV = new EncVecPreProcessingTools(eov, pk);
        EncVecPreProcessingTools toolsVO = new EncVecPreProcessingTools(evo, pk);
        if (!ip.hasNext()) return t1;
        while (ip.hasNext()) {
            EncNode ep2 = EncGraph.nodeSet.get(t2);
            Element anEnum = tools.Enum_P1P2_SD(ep1, ep2);
            Element re = pk.get_G1().newElement(ri());
            Element anNnumr = anEnum.mul(re).getImmutable();
            int cb5 = CT.CT_CMP(anNnumr, re);
            if (cb5 == 0) ep2 = ep1;
            t2 = ip.next();
        }
        HashSet<tokenNode> set1 = P.set;
        set1.remove(t1);
        int cb1 = 0;
        for (tokenNode node : set1) {
            Element re = pk.get_G1().newElement(ri());
            EncNode ep = EncGraph.nodeSet.get(node);
            EncVec esp = new EncVec(es, ep);
            Element encsp = tools.ENCS_SD_SP(esp);
            Element encspr = encsp.mul(re).getImmutable();
            cb1 = CT.CT_CMP(encspr, re);
            if (cb1 == LEFT)
                if (SecureOrienting(Is, Id, node) == LEFT) {
                    PL.set.add(node);
                } else {
                    PR.set.add(node);
                }
        }
        if (!PR.set.isEmpty()) {
            Iterator<tokenNode> itR = PR.set.iterator();
            t1 = itR.next();
            EncNode p1 = EncGraph.nodeSet.get(t1);
            while (itR.hasNext()) {
                t2 = itR.next();
                EncNode p2 = EncGraph.nodeSet.get(t2);
                Element enum1 = toolsOV.Enum_P1P2_SD(p1, p2);
                Element re = pk.get_G1().newElement(ri()).getImmutable();
                Element enum1r = enum1.mul(re).getImmutable();
                cb1 = CT.CT_CMP(enum1r, re);
                if (cb1 == 0) t1 = t2;
            }
        } else {
            Iterator<tokenNode> itL = PL.set.iterator();
            t1 = itL.next();
            EncNode p1 = EncGraph.nodeSet.get(t1);

            while (itL.hasNext()) {
                t2 = itL.next();
                EncNode p2 = EncGraph.nodeSet.get(t2);
                Element enum1 = toolsVO.Enum_P1P2_SD(p1, p2);
                Element re = pk.get_G1().newElement(ri()).getImmutable();
                Element enum1r = enum1.mul(re).getImmutable();
                cb1 = CT.CT_CMP(enum1r, re);
                if (cb1 == 0) t1 = t2;
            }
        }


        return t1;
    }
    //A算法：贪心最近法
    //Orient-Split-sCan-Hop (OSCH)
    //Orient-Split-Pull-Hop (OSPH)
    //
    public tokenNode[] SecureBridging(tokenNode Is, tokenNode Id, StopSet Pmid, StopSet Phigh) {

        return new tokenNode[0];
    }
}
